
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <memory>

#include <iostream>

#include "Blit.h"
#include "Camera.h"
#include "CustomMaterial.hpp"
#include "Geometry.h"
#include "Lights.hpp"
#include "Object.h"
#include "RenderContext.h"
#include "Shader.h"
#include "Texture.h"
#include "Window.h"

using namespace Umikaze;
using namespace Core;

int main() {

  int width = 1600;
  int height = 1200;
  auto &window = Window::instance();
  window->init(width, height);
  std::shared_ptr<Geometry> sphereGeometry =
      std::make_shared<SphereGeometry>(1.0, 64, 64);
  std::shared_ptr<Geometry> planeGeometry =
      std::make_shared<PlaneGeometry>(16.0f, 16.0f);

  std::shared_ptr<Geometry> cubeGeometry =
      std::make_shared<CubeGeometry>(2, 2, 2);

  auto material = std::make_shared<PbrMaterial>();
  material->setMetallic(0.5f);
  material->setRoughness(0.1f);

  auto phongMaterial = std::make_shared<PhongMaterial>();

  auto mat = glm::lookAt(glm::vec3(10, 10, 10), glm::vec3(0, 0, 0),
                         glm::vec3(0, 1, 0));

  auto wife = std::make_shared<ImageTexture>("wife.jpg", true);
  material->_map = wife;
  material->_color = glm::vec3(0.0, 0.0, 0.0);

  glm::vec3 position(0, 0, 0);
  glm::vec3 rotation(0.0, 0, 0);
  glm::vec3 scale(1, 1, 1);

  gDefaultCamera->_position = glm::vec3(0.0f, 0.0f, 3.0);

  std::vector<std::shared_ptr<Object>> objects;

  glm::vec3 cubePositions[] = {
      glm::vec3(0.0f, 0.0f, 0.0f),    glm::vec3(2.0f, 5.0f, -15.0f),
      glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(-3.8f, -2.0f, -12.3f),
      glm::vec3(2.4f, -0.4f, -3.5f),  glm::vec3(-1.7f, 3.0f, -7.5f),
      glm::vec3(1.3f, -2.0f, -2.5f),  glm::vec3(1.5f, 2.0f, -2.5f),
      glm::vec3(1.5f, 0.2f, -1.5f),   glm::vec3(-1.3f, 1.0f, -1.5f)};

  for (auto i = 0; i < 10; ++i) {
    auto object = std::make_shared<Object>(cubeGeometry, material,
                                           cubePositions[i], rotation, scale);
    objects.push_back(object);
  }

  auto plane = std::make_shared<Object>(
      planeGeometry, material, glm::vec3(0.0, -5.0, 0.0),
      glm::vec3(90.0, 0.0, 0.0), glm::vec3(1.0));
  objects.push_back(plane);

  std::shared_ptr<RenderContext> context = std::make_shared<RenderContext>();

  DirectionalLight light1;
  light1._colorAndIntensity = glm::vec4(0.5f, 0.5f, 0.5f, 5.f);
  light1._direction = glm::vec4(0, -1.0f, 0.0f, 0.0f);

  auto lights = std::make_shared<Lights>();
  lights->addDirectionalLight(light1);
  lights->setAmbient({0.4, 0.4, 0.4, 1.0});

  int32_t pixelWidth = Window::instance()->getPixelWidth();
  int32_t pixelHeight = Window::instance()->getPixelHeight();

  std::shared_ptr<CubeTexture> skyBox =
      std::make_shared<CubeTexture>("skybox/", ".jpg");

  gDefaultCamera->_near = 0.01f;

  uint32_t offsetIndex = 0;
  uint32_t accu = 0;

  auto depthTexture =
      std::make_shared<RenderTexture>(1024, 1024, DepthStencilFormat::DEPTH24);
  auto depthTarget = std::make_shared<RenderTarget>(depthTexture, true);

  gDefaultCamera->_far = 20;

  while (!window->shouldClose()) {
    window->startDraw();

    context->setClearColor(0.5f, 0.2f, 0.0f, 0.0f);
    context->setClearBuffer(1);
    context->setDepthTest(true);
    context->setCullFace(false);
    context->setCullFaceMode(123);

    context->setCameraProperties(gDefaultCamera);

    context->setRenderTarget(depthTarget);

    auto lightMat = lights->getDirectionalLightSpaceMatrix(0, gDefaultCamera);
    material->setShadowMap(depthTexture, lightMat);
    material->setLight(lights->getLightData());

    context->drawShadow(objects, lightMat);

    context->setRenderTarget(nullptr);

    context->draw(objects);

    context->drawSkyBox(skyBox);
    window->endDraw();

    offsetIndex++;
    offsetIndex %= 16;

    accu++;
  }

  return 1;
}